package ord2.exec;

import java.io.File;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import ord2.core.Result;
import ord2.core.StringQuery;
import ord2.database.DatabaseConnector;
import ord2.notifier.Notifier;
import ord2.search.Searcher;

/**
 * Class that is gonna do the notification process accessing database and getting
 * notifiers.
 *
 * @author José Ivan
 * @author Edviges
 */public final class NotifierManager {
    
    private LinkedList<Searcher> searchers = new LinkedList<Searcher>();
    private LinkedList<DatabaseConnector> cons = new LinkedList<DatabaseConnector>();
    private HashMap<String, Notifier> nots = new HashMap<String, Notifier>();
    private int interval = 0;
    
    public NotifierManager(int interval) {
        
        this.interval = interval;
    }
    
    public void addSearcher(Searcher s) {
        
        if (s == null) {
            
            throw new NullPointerException("Searcher cannot be null.");
        }
        
        this.searchers.add(s);
    }
    
    public void addNotifier(String type, Notifier inst) {
        
        if (inst == null) {
            
            throw new NullPointerException("Notifier can not be null");
        }
        
        this.nots.put(type, inst);
    }
    
    public void addDatabaseConnector(DatabaseConnector dbc) {
        
        if (dbc == null) {
            
            throw new NullPointerException("DatabaseConnector cannot be null");
        }
        
        this.cons.add(dbc);
    }
    
    public void start() {
        
        (new Thread() {
            
            @Override
            public void run() {
                
                while (true) {
                    
                    try {
                     
                        processNotifications();
                        Thread.sleep(interval * 1000);
                    } catch (InterruptedException ie) {}
                }
            }
        }).start();
    }
    
    public void stop() {
        
        throw new UnsupportedOperationException();
    }
    
    @SuppressWarnings({"unchecked", "unchecked"})
    private void processNotifications() {
        
        for (DatabaseConnector dc : this.cons) {
            try {
                
                Result[] bagaca = dc.query(new StringQuery("select * from `queries`"));
                if (bagaca != null) {

                    ResultSet rs = (ResultSet) bagaca[0].getValue() ;
                    while (rs.next()) {

                        for (Searcher s : this.searchers) {

                            List<Result<File>> l = s.query(new StringQuery(rs.getString("query")));
                            if (l != null && l.size() > 0) {

                                ResultSet rsq = (ResultSet) dc.query(
                                        new StringQuery("select * from `notification` where `qid` = '"
                                        + rs.getString("id") +"';" ))[0].getValue();
                                while (rsq.next()) {

                                    //TODO add data
                                    ResultSet rst = (ResultSet) dc.query(
                                        new StringQuery("select * from `notified` where `nid` = '"
                                            + rsq.getString("id") +"' and `date` = CURDATE();" ))[0].getValue();

                                    if (!rst.next()) {

                                        String type = rsq.getString("tid");
                                        Notifier n = this.nots.get(type);
                                        if (n != null) {

                                            String nid = rsq.getString("id");
                                            if (n.notify(rsq.getString("destination"),
                                                    (Result<File>[])l.toArray(new Result[0]))) {

                                                dc.query(new StringQuery("insert into `notified` (`nid`, `date`) values('" + nid +"', CURDATE())"));
                                            }
                                        }
                                    }
                                    rst.close();
                                }
                                rsq.close();
                            }
                        }
                    }
                    rs.close();
                }                
            } catch(Throwable t) {
                //TODO Add log
                t.printStackTrace();
            }
        }
    }
}
